package com.yituo.mjworld.mvc.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPayConstants;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.yituo.mjworld.core.utils.Constant;
import com.yituo.mjworld.core.utils.OtherTool;
import com.yituo.mjworld.core.web.core.Result;
import com.yituo.mjworld.mvc.entity.UserData;
import com.yituo.mjworld.mvc.entity.web.WxCache;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.Writer;
import java.util.*;

@Service
public class WxServiceImpl {


  /**
   * 扩展xstream使其支持CDATA
   */
  private static XStream xstream = new XStream(new XppDriver() {
    @Override
    public HierarchicalStreamWriter createWriter(Writer out) {
      return new PrettyPrintWriter(out) {
        //增加CDATA标记
        boolean cdata = true;

        @Override
        @SuppressWarnings("rawtypes")
        public void startNode(String name, Class clazz) {
          super.startNode(name, clazz);
        }

        @Override
        protected void writeText(QuickWriter writer, String text) {
          if (cdata) {
            writer.write("<![CDATA[");
            writer.write(text);
            writer.write("]]>");
          } else {
            writer.write(text);
          }
        }
      };
    }
  });


  /**
   * 获取微信的访问Token
   *
   * @return
   */
  public JSONObject getWxAccessToken(String code) throws IOException {
    String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
        "appid=" + WxConfig.APP_ID + "" +
        "&secret=" + WxConfig.APP_SECRET + "" +
        "&code=" + code + "" +
        "&grant_type=authorization_code";
    DefaultHttpClient httpClient = new DefaultHttpClient();
    HttpGet httpGet = new HttpGet(url);
    // 执行请求
    HttpResponse response = httpClient.execute(httpGet);
    JSONObject result = (JSONObject) JSONObject.parse(EntityUtils.toString(response.getEntity(), "utf-8"));
    return result;
  }

  /**
   * 获取微信的访问的JSSDK_ticket
   *
   * @return
   */
  public JSONObject getJsApiTicket(String access_token) throws IOException {
    String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi";
    DefaultHttpClient httpClient = new DefaultHttpClient();
    HttpGet httpGet = new HttpGet(url);
    // 执行请求
    HttpResponse response = httpClient.execute(httpGet);
    JSONObject result = (JSONObject) JSONObject.parse(EntityUtils.toString(response.getEntity(), "utf-8"));
    return result;
  }

  /**
   * 获取微信全局的access_token
   *
   * @return
   */
  public JSONObject getBaseAccessToken() throws IOException {
//    https请求方式: GEThttps://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + WxConfig.APP_ID + "&secret=" + WxConfig.APP_SECRET;
    DefaultHttpClient httpClient = new DefaultHttpClient();
    HttpGet httpGet = new HttpGet(url);
    // 执行请求
    HttpResponse response = httpClient.execute(httpGet);
    JSONObject result = (JSONObject) JSONObject.parse(EntityUtils.toString(response.getEntity(), "utf-8"));
    return result;
  }

  public JSONObject getWxConfig(String ticket, String url) {
    JSONObject config = new JSONObject();
    // 准备URL签名的参数
    String noncestr = OtherTool.getUUID().substring(0, 16);
    long timestamp = System.currentTimeMillis();
    // 生成签名的字符串
    String signature = "jsapi_ticket=" + ticket +
        "&noncestr=" + noncestr +
        "&timestamp=" + timestamp +
        "&url=" + url;
    // SHA1签名
    System.out.println(signature);
    signature = OtherTool.getSha1(signature);
    System.out.println(signature);
    config.put("debug", true);// 开启调试模式,调用的所有api的返回值会在客户端alert出来，若要查看传入的参数，可以在pc端打开，参数信息会通过log打出，仅在pc端时才会打印。
    config.put("appId", WxConfig.APP_ID);// 必填，公众号的唯一标识
    config.put("timestamp", timestamp); // 必填，生成签名的时间戳
    config.put("nonceStr", noncestr);// 必填，生成签名的随机串
    config.put("signature", signature);// 必填，签名，见附录1

    List<String> list = new ArrayList<String>();
    list.add("scanQRCode");
    list.add("chooseWXPay");
    config.put("jsApiList", list);// 必填，需要使用的JS接口列表，所有JS接口列表见附录2
    return config;
  }

  /**
   * 拉取用户信息
   *
   * @param accessToken 访问的token
   * @param openId      用户在公众号下的唯一ID
   * @return
   * @throws IOException
   */
  public JSONObject getWxUserInfo(String accessToken, String openId) throws IOException {
    String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN";
    DefaultHttpClient httpClient = new DefaultHttpClient();
    HttpGet httpGet = new HttpGet(url);
    // 执行请求
    HttpResponse response = httpClient.execute(httpGet);
    JSONObject result = (JSONObject) JSONObject.parse(EntityUtils.toString(response.getEntity(), "utf-8"));
    return result;
  }

  /**
   * 刷新token和ticket
   *
   * @param openId
   * @return
   */
  public Result refreshTokenAndTicket(String openId) throws IOException {
    Result rs = new Result();
    WxCache wxCache = UserData.getWxCacheMap().get(openId);
    if (wxCache == null) {
      wxCache = new WxCache();
      wxCache.setOpenId(openId);
    }
    JSONObject token = this.getBaseAccessToken();
    if (token != null && token.getInteger("errcode") == null) {
      String access_token = token.getString("access_token");
      wxCache.setToken(access_token);
      wxCache.setTokenCreateTime(new Date(System.currentTimeMillis()));
      JSONObject ticket = this.getJsApiTicket(access_token);
      if (ticket != null && ticket.getInteger("errcode") == 0) {
        String js_ticket = ticket.getString("ticket");
        wxCache.setTicket(js_ticket);
        wxCache.setTicketCreateTime(new Date(System.currentTimeMillis()));
        UserData.getWxCacheMap().put(openId, wxCache);
        return rs.setResult(true);
      } else {
        return rs.setResult(false).setMsg(ticket.getString("ticket"));
      }
    } else {
      return new Result().setResult(false).setMsg(token.getString("errmsg"));
    }
  }

  /**
   * 查询微信订单的接口
   *
   * @param tradeNo 本站存储的商户订单号
   * @return
   * @throws IOException
   */
  public Map<String, String> orderQuery(String tradeNo) throws IOException {

    // 微信查询订单的接口
    String url = "https://api.mch.weixin.qq.com/pay/orderquery";

    // 提交的参数
    Map<String, String> signObj = new HashMap<String, String>();
    signObj.put("appid", WxConfig.APP_ID);
    signObj.put("mch_id", WxConfig.MCH_ID);
    signObj.put("nonce_str", OtherTool.getUUID());
    signObj.put("out_trade_no", tradeNo);
    String signature = null;
    String http_post_body = null;
    try {
      // 签名
      signature = WXPayUtil.generateSignature(signObj, WxConfig.API_KEY, WXPayConstants.SignType.MD5);
      signObj.put("sign", signature);
      // 转换为提交的参数
      http_post_body = WXPayUtil.mapToXml(signObj);
      // 调用微信查询订单接口
      DefaultHttpClient httpClient = new DefaultHttpClient();
      HttpPost post = new HttpPost(url);
      HttpEntity httpEntity = new StringEntity(http_post_body);
      post.setEntity(httpEntity);
      HttpResponse response = httpClient.execute(post);
      String responseText = EntityUtils.toString(response.getEntity(), "UTF-8");
      System.out.println("响应文本:" + responseText);
      Map<String, String> result = null;
      result = WXPayUtil.xmlToMap(responseText);
      return result;
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * 统一下单接口
   *
   * @param openId
   * @return
   */
  public Map<String, String> unifiedorder(String openId, String tradeNo, String client_ip, int total_fee) throws IOException {
    String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    // 提交的参数
    Map<String, String> signObj = new HashMap<String, String>();
    signObj.put("appid", WxConfig.APP_ID);
    signObj.put("mch_id", WxConfig.MCH_ID);
    signObj.put("device_info", WxConfig.DEVICE_INFO);
    signObj.put("nonce_str", OtherTool.getUUID());
    signObj.put("body", "bbbb");
    signObj.put("attach", "aaa");
    signObj.put("out_trade_no", tradeNo);
    signObj.put("total_fee", total_fee + "");
    signObj.put("spbill_create_ip", client_ip);
    signObj.put("notify_url", Constant.getDomainPro() + "api/order/wxPayNotify");
    signObj.put("trade_type", "JSAPI");
    signObj.put("openid", openId);
    String http_post_body = "";
    try {
      http_post_body = WXPayUtil.generateSignedXml(signObj, WxConfig.API_KEY, WXPayConstants.SignType.MD5);
      System.out.println("MD5签名成功:" + http_post_body);
    } catch (Exception e) {
      System.out.println("签名失败!");
      return null;
    }
    // 调用微信统一下单接口
    DefaultHttpClient httpClient = new DefaultHttpClient();
    HttpPost post = new HttpPost(url);
    HttpEntity httpEntity = new StringEntity(http_post_body);
    post.setEntity(httpEntity);
    HttpResponse response = httpClient.execute(post);
    String responseText = EntityUtils.toString(response.getEntity(), "UTF-8");
    System.out.println("响应文本:" + responseText);
    Map<String, String> result = null;
    try {
      result = WXPayUtil.xmlToMap(responseText);
      return result;
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * 获取微信支付参数签名
   *
   * @param result
   * @return
   */
  public Map<String, String> getWxPayConfig(Map<String, String> result) throws IOException {

    Map<String, String> wxPayConfig = new HashMap<String, String>();
//    Map<String, Object> wxPayConfig = new HashMap<String, Object>();
    wxPayConfig.put("appId", WxConfig.APP_ID);
    wxPayConfig.put("timeStamp", System.currentTimeMillis() + "");
    wxPayConfig.put("nonceStr", OtherTool.getUUID());
    wxPayConfig.put("package", "prepay_id=" + result.get("prepay_id"));
    wxPayConfig.put("signType", "MD5");
    String paySign = null;
    try {
      paySign = WXPayUtil.generateSignature(wxPayConfig, WxConfig.API_KEY, WXPayConstants.SignType.MD5);
    } catch (Exception e) {
      e.printStackTrace();
      // 签名失败
      return null;
    }
    // 签名加入到参数map中
    wxPayConfig.put("paySign", paySign);
    return wxPayConfig;
  }

}
